home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 2 / AACD 2.iso / AACD / Magazine / GraphicsCards / StormMesa / src-glut / glut_event.c < prev    next >
C/C++ Source or Header  |  1998-12-15  |  45KB  |  1,345 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1997, 1998. */
  3.  
  4. /* This program is freely distributable without licensing fees
  5.    and is provided without guarantee or warrantee expressed or
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <errno.h>
  11. #include <assert.h>
  12. #include <string.h>  /* Some FD_ZERO macros use memset without
  13.                         prototyping memset. */
  14.  
  15. /* Much of the following #ifdef logic to include the proper
  16.    prototypes for the select system call is based on logic
  17.    from the X11R6.3 version of <X11/Xpoll.h>. */
  18.  
  19. #if !defined(_WIN32)
  20. # ifdef __sgi
  21. #  include <bstring.h>    /* prototype for bzero used by FD_ZERO */
  22. # endif
  23. # if (defined(SVR4) || defined(CRAY) || defined(AIXV3)) && !defined(FD_SETSIZE)
  24. #  include <sys/select.h> /* select system call interface */
  25. #  ifdef luna
  26. #   include <sysent.h>
  27. #  endif
  28. # endif
  29.   /* AIX 4.2 fubar-ed <sys/select.h>, so go to heroic measures to get it */
  30. # if defined(AIXV4) && !defined(NFDBITS)
  31. #  include <sys/select.h>
  32. # endif
  33. #endif /* !_WIN32 */
  34.  
  35. #include <sys/types.h>
  36.  
  37. #if !defined(_WIN32)
  38. # if defined(__vms) && ( __VMS_VER < 70000000 )
  39. #  include <sys/time.h>
  40. # else
  41. #  ifndef __vms
  42. #   include <sys/time.h>
  43. #  endif
  44. # endif
  45. # include <unistd.h>
  46. # include <X11/Xlib.h>
  47. # include <X11/keysym.h>
  48. #else
  49. # ifdef __CYGWIN32__
  50. #  include <sys/time.h>
  51. # else
  52. #  include <sys/timeb.h>
  53. # endif
  54. # ifdef __hpux
  55.    /* XXX Bert Gijsbers <bert@mc.bio.uva.nl> reports that HP-UX
  56.       needs different keysyms for the End, Insert, and Delete keys
  57.       to work on an HP 715.  It would be better if HP generated
  58.       standard keysyms for standard keys. */
  59. #  include <X11/HPkeysym.h>
  60. # endif
  61. #endif /* !_WIN32 */
  62.  
  63. #if defined(__vms) && ( __VMS_VER < 70000000 )
  64. #include <ssdef.h>
  65. #include <psldef.h>
  66. extern int SYS$CLREF(int efn);
  67. extern int SYS$SETIMR(unsigned int efn, struct timeval *timeout, void *ast,
  68.   unsigned int request_id, unsigned int flags);
  69. extern int SYS$WFLOR(unsigned int efn, unsigned int mask);
  70. extern int SYS$CANTIM(unsigned int request_id, unsigned int mode);
  71. #endif /* __vms, VMs 6.2 or earlier */
  72.  
  73. #include "glutint.h"
  74.  
  75. static GLUTtimer *freeTimerList = NULL;
  76.  
  77. GLUTidleCB __glutIdleFunc = NULL;
  78. GLUTtimer *__glutTimerList = NULL;
  79. #ifdef SUPPORT_FORTRAN
  80. GLUTtimer *__glutNewTimer;
  81. #endif
  82. GLUTwindow *__glutWindowWorkList = NULL;
  83. GLUTmenu *__glutMappedMenu;
  84. GLUTmenu *__glutCurrentMenu = NULL;
  85.  
  86. void (*__glutUpdateInputDeviceMaskFunc) (GLUTwindow *);
  87. #if !defined(_WIN32)
  88. void (*__glutMenuItemEnterOrLeave)(GLUTmenuItem * item, int num, int type) = NULL;
  89. void (*__glutFinishMenu)(Window win, int x, int y);
  90. void (*__glutPaintMenu)(GLUTmenu * menu);
  91. void (*__glutStartMenu)(GLUTmenu * menu, GLUTwindow * window, int x, int y, int x_win, int y_win);
  92. GLUTmenu * (*__glutGetMenuByNum)(int menunum);
  93. GLUTmenuItem * (*__glutGetMenuItem)(GLUTmenu * menu, Window win, int *which);
  94. GLUTmenu * (*__glutGetMenu)(Window win);
  95. #endif
  96.  
  97. Atom __glutMotifHints = None;
  98. /* Modifier mask of ~0 implies not in core input callback. */
  99. unsigned int __glutModifierMask = (unsigned int) ~0;
  100. int __glutWindowDamaged = 0;
  101.  
  102. void APIENTRY
  103. glutIdleFunc(GLUTidleCB idleFunc)
  104. {
  105.   __glutIdleFunc = idleFunc;
  106. }
  107.  
  108. void APIENTRY
  109. glutTimerFunc(unsigned int interval, GLUTtimerCB timerFunc, int value)
  110. {
  111.   GLUTtimer *timer, *other;
  112.   GLUTtimer **prevptr;
  113.   struct timeval now;
  114.  
  115.   if (!timerFunc)
  116.     return;
  117.  
  118.   if (freeTimerList) {
  119.     timer = freeTimerList;
  120.     freeTimerList = timer->next;
  121.   } else {
  122.     timer = (GLUTtimer *) malloc(sizeof(GLUTtimer));
  123.     if (!timer)
  124.       __glutFatalError("out of memory.");
  125.   }
  126.  
  127.   timer->func = timerFunc;
  128. #if defined(__vms) && ( __VMS_VER < 70000000 )
  129.   /* VMS time is expressed in units of 100 ns */
  130.   timer->timeout.val = interval * TICKS_PER_MILLISECOND;
  131. #else
  132.   timer->timeout.tv_sec = (int) interval / 1000;
  133.   timer->timeout.tv_usec = (int) (interval % 1000) * 1000;
  134. #endif
  135.   timer->value = value;
  136.   timer->next = NULL;
  137.   GETTIMEOFDAY(&now);
  138.   ADD_TIME(timer->timeout, timer->timeout, now);
  139.   prevptr = &__glutTimerList;
  140.   other = *prevptr;
  141.   while (other && IS_AFTER(other->timeout, timer->timeout)) {
  142.     prevptr = &other->next;
  143.     other = *prevptr;
  144.   }
  145.   timer->next = other;
  146. #ifdef SUPPORT_FORTRAN
  147.   __glutNewTimer = timer;  /* for Fortran binding! */
  148. #endif
  149.   *prevptr = timer;
  150. }
  151.  
  152. void
  153. handleTimeouts(void)
  154. {
  155.   struct timeval now;
  156.   GLUTtimer *timer;
  157.  
  158.   /* Assumption is that __glutTimerList is already determined
  159.      to be non-NULL. */
  160.   GETTIMEOFDAY(&now);
  161.   while (IS_AT_OR_AFTER(__glutTimerList->timeout, now)) {
  162.     timer = __glutTimerList;
  163.     timer->func(timer->value);
  164.     __glutTimerList = timer->next;
  165.     timer->next = freeTimerList;
  166.     freeTimerList = timer;
  167.     if (!__glutTimerList)
  168.       break;
  169.   }
  170. }
  171.  
  172. void
  173. __glutPutOnWorkList(GLUTwindow * window, int workMask)
  174. {
  175.   if (window->workMask) {
  176.     /* Already on list; just OR in new workMask. */
  177.     window->workMask |= workMask;
  178.   } else {
  179.     /* Update work mask and add to window work list. */
  180.     window->workMask = workMask;
  181.     /* Assert that if the window does not have a
  182.        workMask already, the window should definitely
  183.        not be the head of the work list. */
  184.     assert(window != __glutWindowWorkList);
  185.     window->prevWorkWin = __glutWindowWorkList;
  186.     __glutWindowWorkList = window;
  187.   }
  188. }
  189.  
  190. void
  191. __glutPostRedisplay(GLUTwindow * window, int layerMask)
  192. {
  193.   int shown = (layerMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) ?
  194.     window->shownState : window->overlay->shownState;
  195.  
  196.   /* Post a redisplay if the window is visible (or the
  197.      visibility of the window is unknown, ie. window->visState
  198.      == -1) _and_ the layer is known to be shown. */
  199.   if (window->visState != GLUT_HIDDEN
  200.     && window->visState != GLUT_FULLY_COVERED && shown) {
  201.     __glutPutOnWorkList(window, layerMask);
  202.   }
  203. }
  204.  
  205. /* CENTRY */
  206. void APIENTRY
  207. glutPostRedisplay(void)
  208. {
  209.   __glutPostRedisplay(__glutCurrentWindow, GLUT_REDISPLAY_WORK);
  210. }
  211.  
  212. /* The advantage of this routine is that it saves the cost of a
  213.    glutSetWindow call (entailing an expensive OpenGL context switch),
  214.    particularly useful when multiple windows need redisplays posted at
  215.    the same times.  See also glutPostWindowOverlayRedisplay. */
  216. void APIENTRY
  217. glutPostWindowRedisplay(int win)
  218. {
  219.   __glutPostRedisplay(__glutWindowList[win - 1], GLUT_REDISPLAY_WORK);
  220. }
  221.  
  222. /* ENDCENTRY */
  223. static GLUTeventParser *eventParserList = NULL;
  224.  
  225. /* __glutRegisterEventParser allows another module to register
  226.    to intercept X events types not otherwise acted on by the
  227.    GLUT processEventsAndTimeouts routine.  The X Input
  228.    extension support code uses an event parser for handling X
  229.    Input extension events.  */
  230.  
  231. void
  232. __glutRegisterEventParser(GLUTeventParser * parser)
  233. {
  234.   parser->next = eventParserList;
  235.   eventParserList = parser;
  236. }
  237.  
  238. static void
  239. markWindowHidden(GLUTwindow * window)
  240. {
  241.   if (GLUT_HIDDEN != window->visState) {
  242.     GLUTwindow *child;
  243.  
  244.     if (window->windowStatus) {
  245.       window->visState = GLUT_HIDDEN;
  246.       __glutSetWindow(window);
  247.       window->windowStatus(GLUT_HIDDEN);
  248.     }
  249.     /* An unmap is only reported on a single window; its
  250.        descendents need to know they are no longer visible. */
  251.     child = window->children;
  252.     while (child) {
  253.       markWindowHidden(child);
  254.       child = child->siblings;
  255.     }
  256.   }
  257. }
  258.  
  259. #if !defined(_WIN32)
  260.  
  261. static void
  262. purgeStaleWindow(Window win)
  263. {
  264.   GLUTstale **pEntry = &__glutStaleWindowList;
  265.   GLUTstale *entry = __glutStaleWindowList;
  266.  
  267.   /* Tranverse singly-linked stale window list look for the
  268.      window ID. */
  269.   while (entry) {
  270.     if (entry->win == win) {
  271.       /* Found it; delete it. */
  272.       *pEntry = entry->next;
  273.       free(entry);
  274.       return;
  275.     } else {
  276.       pEntry = &entry->next;
  277.       entry = *pEntry;
  278.     }
  279.   }
  280. }
  281.  
  282. /* Unlike XNextEvent, if a signal arrives,
  283.    interruptibleXNextEvent will return (with a zero return
  284.    value).  This helps GLUT drop out of XNextEvent if a signal
  285.    is delivered.  The intent is so that a GLUT program can call 
  286.    glutIdleFunc in a signal handler to register an idle func
  287.    and then immediately get dropped into the idle func (after
  288.    returning from the signal handler).  The idea is to make
  289.    GLUT's main loop reliably interruptible by signals. */
  290. static int
  291. interruptibleXNextEvent(Display * dpy, XEvent * event)
  292. {
  293.   fd_set fds;
  294.   int rc;
  295.  
  296.   /* Flush X protocol since XPending does not do this
  297.      implicitly. */
  298.   XFlush(__glutDisplay);
  299.   for (;;) {
  300.     if (XPending(__glutDisplay)) {
  301.       XNextEvent(dpy, event);
  302.       return 1;
  303.     }
  304.     FD_ZERO(&fds);
  305.     FD_SET(__glutConnectionFD, &fds);
  306.     rc = select(__glutConnectionFD + 1, &fds,
  307.       NULL, NULL, NULL);
  308.     if (rc < 0) {
  309.       if (errno == EINTR) {
  310.         return 0;
  311.       } else {
  312.         __glutFatalError("select error.");
  313.       }
  314.     }
  315.   }
  316. }
  317.  
  318. #endif
  319.  
  320. static void
  321. processEventsAndTimeouts(void)
  322. {
  323.   do {
  324. #if defined(_WIN32)
  325.     MSG event;
  326.  
  327.     if(!GetMessage(&event, NULL, 0, 0))    /* bail if no more messages */
  328.       exit(0);
  329.     TranslateMessage(&event);        /* translate virtual-key messages */
  330.     DispatchMessage(&event);        /* call the window proc */
  331.     /* see win32_event.c for event (message) processing procedures */
  332. #else
  333.     static int mappedMenuButton;
  334.     GLUTeventParser *parser;
  335.     XEvent event, ahead;
  336.     GLUTwindow *window;
  337.     GLUTkeyboardCB keyboard;
  338.     GLUTspecialCB special;
  339.     int gotEvent, width, height;
  340.  
  341.     gotEvent = interruptibleXNextEvent(__glutDisplay, &event);
  342.     if (gotEvent) {
  343.       switch (event.type) {
  344.       case MappingNotify:
  345.         XRefreshKeyboardMapping((XMappingEvent *) & event);
  346.         break;
  347.       case ConfigureNotify:
  348.         window = __glutGetWindow(event.xconfigure.window);
  349.         if (window) {
  350.           if (window->win != event.xconfigure.window) {
  351.             /* Ignore ConfigureNotify sent to the overlay
  352.                planes. GLUT could get here because overlays
  353.                select for StructureNotify events to receive
  354.                DestroyNotify. */
  355.             break;
  356.           }
  357.           width = event.xconfigure.width;
  358.           height = event.xconfigure.height;
  359.           if (width != window->width || height != window->height) {
  360.             if (window->overlay) {
  361.               XResizeWindow(__glutDisplay, window->overlay->win, width, height);
  362.             }
  363.             window->width = width;
  364.             window->height = height;
  365.             __glutSetWindow(window);
  366.             /* Do not execute OpenGL out of sequence with
  367.                respect to the XResizeWindow request! */
  368.             glXWaitX();
  369.             window->reshape(width, height);
  370.             window->forceReshape = False;
  371.             /* A reshape should be considered like posting a
  372.                repair; this is necessary for the "Mesa
  373.                glXSwapBuffers to repair damage" hack to operate
  374.                correctly.  Without it, there's not an initial
  375.                back buffer render from which to blit from when
  376.                damage happens to the window. */
  377.             __glutPostRedisplay(window, GLUT_REPAIR_WORK);
  378.           }
  379.         }
  380.         break;
  381.       case Expose:
  382.         /* compress expose events */
  383.         while (XEventsQueued(__glutDisplay, QueuedAfterReading)
  384.           > 0) {
  385.           XPeekEvent(__glutDisplay, &ahead);
  386.           if (ahead.type != Expose ||
  387.             ahead.xexpose.window != event.xexpose.window) {
  388.             break;
  389.           }
  390.           XNextEvent(__glutDisplay, &event);
  391.         }
  392.         if (event.xexpose.count == 0) {
  393.           GLUTmenu *menu;
  394.  
  395.           if (__glutMappedMenu &&
  396.             (menu = __glutGetMenu(event.xexpose.window))) {
  397.             __glutPaintMenu(menu);
  398.           } else {
  399.             window = __glutGetWindow(event.xexpose.window);
  400.             if (window) {
  401.               if (window->win == event.xexpose.window) {
  402.                 __glutPostRedisplay(window, GLUT_REPAIR_WORK);
  403.               } else if (window->overlay && window->overlay->win == event.xexpose.window) {
  404.                 __glutPostRedisplay(window, GLUT_OVERLAY_REPAIR_WORK);
  405.               }
  406.             }
  407.           }
  408.         } else {
  409.           /* there are more exposes to read; wait to redisplay */
  410.         }
  411.         break;
  412.       case ButtonPress:
  413.       case ButtonRelease:
  414.         if (__glutMappedMenu && event.type == ButtonRelease
  415.           && mappedMenuButton == event.xbutton.button) {
  416.           /* Menu is currently popped up and its button is
  417.              released. */
  418.           __glutFinishMenu(event.xbutton.window, event.xbutton.x, event.xbutton.y);
  419.         } else {
  420.           window = __glutGetWindow(event.xbutton.window);
  421.           if (window) {
  422.             GLUTmenu *menu;
  423.         int menuNum;
  424.  
  425.             menuNum = window->menu[event.xbutton.button - 1];
  426.             /* Make sure that __glutGetMenuByNum is only called if there
  427.            really is a menu present. */
  428.             if ((menuNum > 0) && (menu = __glutGetMenuByNum(menuNum))) {
  429.               if (event.type == ButtonPress && !__glutMappedMenu) {
  430.                 __glutStartMenu(menu, window,
  431.                   event.xbutton.x_root, event.xbutton.y_root,
  432.                   event.xbutton.x, event.xbutton.y);
  433.                 mappedMenuButton = event.xbutton.button;
  434.               } else {
  435.                 /* Ignore a release of a button with a menu
  436.                    attatched to it when no menu is popped up,
  437.                    or ignore a press when another menu is
  438.                    already popped up. */
  439.               }
  440.             } else if (window->mouse) {
  441.               __glutSetWindow(window);
  442.               __glutModifierMask = event.xbutton.state;
  443.               window->mouse(event.xbutton.button - 1,
  444.                 event.type == ButtonRelease ?
  445.                 GLUT_UP : GLUT_DOWN,
  446.                 event.xbutton.x, event.xbutton.y);
  447.               __glutModifierMask = ~0;
  448.             } else {
  449.               /* Stray mouse events.  Ignore. */
  450.             }
  451.           } else {
  452.             /* Window might have been destroyed and all the 
  453.                events for the window may not yet be received. */
  454.           }
  455.         }
  456.         break;
  457.       case MotionNotify:
  458.         if (!__glutMappedMenu) {
  459.           window = __glutGetWindow(event.xmotion.window);
  460.           if (window) {
  461.             /* If motion function registered _and_ buttons held 
  462.                * down, call motion function...  */
  463.             if (window->motion && event.xmotion.state &
  464.               (Button1Mask | Button2Mask | Button3Mask)) {
  465.               __glutSetWindow(window);
  466.               window->motion(event.xmotion.x, event.xmotion.y);
  467.             }
  468.             /* If passive motion function registered _and_
  469.                buttons not held down, call passive motion
  470.                function...  */
  471.             else if (window->passive &&
  472.                 ((event.xmotion.state &
  473.                     (Button1Mask | Button2Mask | Button3Mask)) ==
  474.                 0)) {
  475.               __glutSetWindow(window);
  476.               window->passive(event.xmotion.x,
  477.                 event.xmotion.y);
  478.             }
  479.           }
  480.         } else {
  481.           /* Motion events are thrown away when a pop up menu
  482.              is active. */
  483.         }
  484.         break;
  485.       case KeyPress:
  486.       case KeyRelease:
  487.         window = __glutGetWindow(event.xkey.window);
  488.         if (!window) {
  489.           break;
  490.         }
  491.     if (event.type == KeyPress) {
  492.       keyboard = window->keyboard;
  493.     } else {
  494.  
  495.       /* If we are ignoring auto repeated keys for this window,
  496.          check if the next event in the X event queue is a KeyPress
  497.          for the exact same key (and at the exact same time) as the
  498.          key being released.  The X11 protocol will send auto
  499.          repeated keys as such KeyRelease/KeyPress pairs. */
  500.  
  501.       if (window->ignoreKeyRepeat) {
  502.         if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
  503.           XPeekEvent(__glutDisplay, &ahead);
  504.           if (ahead.type == KeyPress
  505.             && ahead.xkey.window == event.xkey.window
  506.             && ahead.xkey.keycode == event.xkey.keycode
  507.             && ahead.xkey.time == event.xkey.time) {
  508.         /* Pop off the repeated KeyPress and ignore
  509.            the auto repeated KeyRelease/KeyPress pair. */
  510.             XNextEvent(__glutDisplay, &event);
  511.             break;
  512.           }
  513.         }
  514.       }
  515.       keyboard = window->keyboardUp;
  516.     }
  517.         if (keyboard) {
  518.           char tmp[1];
  519.           int rc;
  520.  
  521.           rc = XLookupString(&event.xkey, tmp, sizeof(tmp),
  522.             NULL, NULL);
  523.           if (rc) {
  524.             __glutSetWindow(window);
  525.             __glutModifierMask = event.xkey.state;
  526.             keyboard(tmp[0],
  527.               event.xkey.x, event.xkey.y);
  528.             __glutModifierMask = ~0;
  529.             break;
  530.           }
  531.         }
  532.     if (event.type == KeyPress) {
  533.       special = window->special;
  534.         } else {
  535.       special = window->specialUp;
  536.     }
  537.         if (special) {
  538.           KeySym ks;
  539.           int key;
  540.  
  541. /* Introduced in X11R6:  (Partial list of) Keypad Functions.  Define
  542.    in place in case compiling against an older pre-X11R6
  543.    X11/keysymdef.h file. */
  544. #ifndef XK_KP_Home
  545. #define XK_KP_Home              0xFF95
  546. #endif
  547. #ifndef XK_KP_Left
  548. #define XK_KP_Left              0xFF96
  549. #endif
  550. #ifndef XK_KP_Up
  551. #define XK_KP_Up                0xFF97
  552. #endif
  553. #ifndef XK_KP_Right
  554. #define XK_KP_Right             0xFF98
  555. #endif
  556. #ifndef XK_KP_Down
  557. #define XK_KP_Down              0xFF99
  558. #endif
  559. #ifndef XK_KP_Prior
  560. #define XK_KP_Prior             0xFF9A
  561. #endif
  562. #ifndef XK_KP_Next
  563. #define XK_KP_Next              0xFF9B
  564. #endif
  565. #ifndef XK_KP_End
  566. #define XK_KP_End               0xFF9C
  567. #endif
  568. #ifndef XK_KP_Insert
  569. #define XK_KP_Insert            0xFF9E
  570. #endif
  571. #ifndef XK_KP_Delete
  572. #define XK_KP_Delete            0xFF9F
  573. #endif
  574.  
  575.           ks = XLookupKeysym((XKeyEvent *) & event, 0);
  576.           /* XXX Verbose, but makes no assumptions about keysym
  577.              layout. */
  578.           switch (ks) {
  579. /* *INDENT-OFF* */
  580.           /* function keys */
  581.           case XK_F1:    key = GLUT_KEY_F1; break;
  582.           case XK_F2:    key = GLUT_KEY_F2; break;
  583.           case XK_F3:    key = GLUT_KEY_F3; break;
  584.           case XK_F4:    key = GLUT_KEY_F4; break;
  585.           case XK_F5:    key = GLUT_KEY_F5; break;
  586.           case XK_F6:    key = GLUT_KEY_F6; break;
  587.           case XK_F7:    key = GLUT_KEY_F7; break;
  588.           case XK_F8:    key = GLUT_KEY_F8; break;
  589.           case XK_F9:    key = GLUT_KEY_F9; break;
  590.           case XK_F10:   key = GLUT_KEY_F10; break;
  591.           case XK_F11:   key = GLUT_KEY_F11; break;
  592.           case XK_F12:   key = GLUT_KEY_F12; break;
  593.           /* directional keys */
  594.       case XK_KP_Left:
  595.           case XK_Left:  key = GLUT_KEY_LEFT; break;
  596.       case XK_KP_Up: /* Introduced in X11R6. */
  597.           case XK_Up:    key = GLUT_KEY_UP; break;
  598.       case XK_KP_Right: /* Introduced in X11R6. */
  599.           case XK_Right: key = GLUT_KEY_RIGHT; break;
  600.       case XK_KP_Down: /* Introduced in X11R6. */
  601.           case XK_Down:  key = GLUT_KEY_DOWN; break;
  602. /* *INDENT-ON* */
  603.  
  604.       case XK_KP_Prior: /* Introduced in X11R6. */
  605.           case XK_Prior:
  606.             /* XK_Prior same as X11R6's XK_Page_Up */
  607.             key = GLUT_KEY_PAGE_UP;
  608.             break;
  609.       case XK_KP_Next: /* Introduced in X11R6. */
  610.           case XK_Next:
  611.             /* XK_Next same as X11R6's XK_Page_Down */
  612.             key = GLUT_KEY_PAGE_DOWN;
  613.             break;
  614.       case XK_KP_Home: /* Introduced in X11R6. */
  615.           case XK_Home:
  616.             key = GLUT_KEY_HOME;
  617.             break;
  618. #ifdef __hpux
  619.           case XK_Select:
  620. #endif
  621.       case XK_KP_End: /* Introduced in X11R6. */
  622.           case XK_End:
  623.             key = GLUT_KEY_END;
  624.             break;
  625. #ifdef __hpux
  626.           case XK_InsertChar:
  627. #endif
  628.       case XK_KP_Insert: /* Introduced in X11R6. */
  629.           case XK_Insert:
  630.             key = GLUT_KEY_INSERT;
  631.             break;
  632. #ifdef __hpux
  633.           case XK_DeleteChar:
  634. #endif
  635.       case XK_KP_Delete: /* Introduced in X11R6. */
  636.             /* The Delete character is really an ASCII key. */
  637.             __glutSetWindow(window);
  638.             keyboard(127,  /* ASCII Delete character. */
  639.               event.xkey.x, event.xkey.y);
  640.             goto skip;
  641.           default:
  642.             goto skip;
  643.           }
  644.           __glutSetWindow(window);
  645.           __glutModifierMask = event.xkey.state;
  646.           special(key, event.xkey.x, event.xkey.y);
  647.           __glutModifierMask = ~0;
  648.         skip:;
  649.         }
  650.         break;
  651.       case EnterNotify:
  652.       case LeaveNotify:
  653.         if (event.xcrossing.mode != NotifyNormal ||
  654.           event.xcrossing.detail == NotifyNonlinearVirtual ||
  655.           event.xcrossing.detail == NotifyVirtual) {
  656.  
  657.           /* Careful to ignore Enter/LeaveNotify events that
  658.              come from the pop-up menu pointer grab and ungrab. 
  659.              Also, ignore "virtual" Enter/LeaveNotify events
  660.              since they represent the pointer passing through
  661.              the window hierarchy without actually entering or
  662.              leaving the actual real estate of a window.  */
  663.  
  664.           break;
  665.         }
  666.         if (__glutMappedMenu) {
  667.           GLUTmenuItem *item;
  668.           int num;
  669.  
  670.           item = __glutGetMenuItem(__glutMappedMenu,
  671.             event.xcrossing.window, &num);
  672.           if (item) {
  673.             __glutMenuItemEnterOrLeave(item, num, event.type);
  674.             break;
  675.           }
  676.         }
  677.         window = __glutGetWindow(event.xcrossing.window);
  678.         if (window) {
  679.           if (window->entry) {
  680.             if (event.type == EnterNotify) {
  681.  
  682.               /* With overlays established, X can report two
  683.                  enter events for both the overlay and normal
  684.                  plane window. Do not generate a second enter
  685.                  callback if we reported one without an
  686.                  intervening leave. */
  687.  
  688.               if (window->entryState != EnterNotify) {
  689.                 int num = window->num;
  690.                 Window xid = window->win;
  691.  
  692.                 window->entryState = EnterNotify;
  693.                 __glutSetWindow(window);
  694.                 window->entry(GLUT_ENTERED);
  695.  
  696.                 if (__glutMappedMenu) {
  697.  
  698.                   /* Do not generate any passive motion events
  699.                      when menus are in use. */
  700.  
  701.                 } else {
  702.  
  703.                   /* An EnterNotify event can result in a
  704.                      "compound" callback if a passive motion
  705.                      callback is also registered. In this case,
  706.                      be a little paranoid about the possibility
  707.                      the window could have been destroyed in the
  708.                      entry callback. */
  709.  
  710.                   window = __glutWindowList[num];
  711.                   if (window && window->passive && window->win == xid) {
  712.                     __glutSetWindow(window);
  713.                     window->passive(event.xcrossing.x, event.xcrossing.y);
  714.                   }
  715.                 }
  716.               }
  717.             } else {
  718.               if (window->entryState != LeaveNotify) {
  719.  
  720.                 /* When an overlay is established for a window
  721.                    already mapped and with the pointer in it,
  722.                    the X server will generate a leave/enter
  723.                    event pair as the pointer leaves (without
  724.                    moving) from the normal plane X window to
  725.                    the newly mapped overlay  X window (or vice
  726.                    versa). This enter/leave pair should not be
  727.                    reported to the GLUT program since the pair
  728.                    is a consequence of creating (or destroying) 
  729.                    the overlay, not an actual leave from the
  730.                    GLUT window. */
  731.  
  732.                 if (XEventsQueued(__glutDisplay, QueuedAfterReading)) {
  733.                   XPeekEvent(__glutDisplay, &ahead);
  734.                   if (ahead.type == EnterNotify &&
  735.                     __glutGetWindow(ahead.xcrossing.window) == window) {
  736.                     XNextEvent(__glutDisplay, &event);
  737.                     break;
  738.                   }
  739.                 }
  740.                 window->entryState = LeaveNotify;
  741.                 __glutSetWindow(window);
  742.                 window->entry(GLUT_LEFT);
  743.               }
  744.             }
  745.           } else if (window->passive) {
  746.             __glutSetWindow(window);
  747.             window->passive(event.xcrossing.x, event.xcrossing.y);
  748.           }
  749.         }
  750.         break;
  751.       case UnmapNotify:
  752.         /* MapNotify events are not needed to maintain
  753.            visibility state since VisibilityNotify events will
  754.            be delivered when a window becomes visible from
  755.            mapping.  However, VisibilityNotify events are not
  756.            delivered when a window is unmapped (for the window
  757.            or its children). */
  758.         window = __glutGetWindow(event.xunmap.window);
  759.         if (window) {
  760.           if (window->win != event.xconfigure.window) {
  761.             /* Ignore UnmapNotify sent to the overlay planes.
  762.                GLUT could get here because overlays select for
  763.                StructureNotify events to receive DestroyNotify. 
  764.              */
  765.             break;
  766.           }
  767.           markWindowHidden(window);
  768.         }
  769.         break;
  770.       case VisibilityNotify:
  771.         window = __glutGetWindow(event.xvisibility.window);
  772.         if (window) {
  773.           /* VisibilityUnobscured+1 = GLUT_FULLY_RETAINED,
  774.              VisibilityPartiallyObscured+1 =
  775.              GLUT_PARTIALLY_RETAINED, VisibilityFullyObscured+1 
  776.              =  GLUT_FULLY_COVERED. */
  777.           int visState = event.xvisibility.state + 1;
  778.  
  779.           if (visState != window->visState) {
  780.             if (window->windowStatus) {
  781.               window->visState = visState;
  782.               __glutSetWindow(window);
  783.               window->windowStatus(visState);
  784.             }
  785.           }
  786.         }
  787.         break;
  788.       case ClientMessage:
  789.         if (event.xclient.data.l[0] == __glutWMDeleteWindow)
  790.           exit(0);
  791.         break;
  792.       case DestroyNotify:
  793.         purgeStaleWindow(event.xdestroywindow.window);
  794.         break;
  795.       case CirculateNotify:
  796.       case CreateNotify:
  797.       case GravityNotify:
  798.       case ReparentNotify:
  799.         /* Uninteresting to GLUT (but possible for GLUT to
  800.            receive). */
  801.         break;
  802.       default:
  803.         /* Pass events not directly handled by the GLUT main
  804.            event loop to any event parsers that have been
  805.            registered.  In this way, X Input extension events
  806.            are passed to the correct handler without forcing
  807.            all GLUT programs to support X Input event handling. 
  808.          */
  809.         parser = eventParserList;
  810.         while (parser) {
  811.           if (parser->func(&event))
  812.             break;
  813.           parser = parser->next;
  814.         }
  815.         break;
  816.       }
  817.     }
  818. #endif /* _WIN32 */
  819.     if (__glutTimerList) {
  820.       handleTimeouts();
  821.     }
  822.   }
  823.   while (XPending(__glutDisplay));
  824. }
  825.  
  826. static void
  827. waitForSomething(void)
  828. {
  829. #if defined(__vms) && ( __VMS_VER < 70000000 )
  830.   static struct timeval zerotime =
  831.   {0};
  832.   unsigned int timer_efn;
  833. #define timer_id 'glut' /* random :-) number */
  834.   unsigned int wait_mask;
  835. #else
  836.   static struct timeval zerotime =
  837.   {0, 0};
  838. #if !defined(_WIN32)
  839.   fd_set fds;
  840. #endif
  841. #endif
  842.   struct timeval now, timeout, waittime;
  843. #if !defined(_WIN32)
  844.   int rc;
  845. #endif
  846.  
  847.   /* Flush X protocol since XPending does not do this
  848.      implicitly. */
  849.   XFlush(__glutDisplay);
  850.   if (XPending(__glutDisplay)) {
  851.     /* It is possible (but quite rare) that XFlush may have
  852.        needed to wait for a writable X connection file
  853.        descriptor, and in the process, may have had to read off
  854.        X protocol from the file descriptor. If XPending is true,
  855.        this case occured and we should avoid waiting in select
  856.        since X protocol buffered within Xlib is due to be
  857.        processed and potentially no more X protocol is on the
  858.        file descriptor, so we would risk waiting improperly in
  859.        select. */
  860.     goto immediatelyHandleXinput;
  861.   }
  862. #if defined(__vms) && ( __VMS_VER < 70000000 )
  863.   timeout = __glutTimerList->timeout;
  864.   GETTIMEOFDAY(&now);
  865.   wait_mask = 1 << (__glutConnectionFD & 31);
  866.   if (IS_AFTER(now, timeout)) {
  867.     /* We need an event flag for the timer. */
  868.     /* XXX The `right' way to do this is to use LIB$GET_EF, but
  869.        since it needs to be in the same cluster as the EFN for
  870.        the display, we will have hack it. */
  871.     timer_efn = __glutConnectionFD - 1;
  872.     if ((timer_efn / 32) != (__glutConnectionFD / 32)) {
  873.       timer_efn = __glutConnectionFD + 1;
  874.     }
  875.     rc = SYS$CLREF(timer_efn);
  876.     rc = SYS$SETIMR(timer_efn, &timeout, NULL, timer_id, 0);
  877.     wait_mask |= 1 << (timer_efn & 31);
  878.   } else {
  879.     timer_efn = 0;
  880.   }
  881.   rc = SYS$WFLOR(__glutConnectionFD, wait_mask);
  882.   if (timer_efn != 0 && SYS$CLREF(timer_efn) == SS$_WASCLR) {
  883.     rc = SYS$CANTIM(timer_id, PSL$C_USER);
  884.   }
  885.   /* XXX There does not seem to be checking of "rc" in the code
  886.      above.  Can any of the SYS$ routines above fail? */
  887. #else /* not vms6.2 or lower */
  888. #if !defined(_WIN32)
  889.   FD_ZERO(&fds);
  890.   FD_SET(__glutConnectionFD, &fds);
  891. #endif
  892.   timeout = __glutTimerList->timeout;
  893.   GETTIMEOFDAY(&now);
  894.   if (IS_AFTER(now, timeout)) {
  895.     TIMEDELTA(waittime, timeout, now);
  896.   } else {
  897.     waittime = zerotime;
  898.   }
  899. #if !defined(_WIN32)
  900.   rc = select(__glutConnectionFD + 1, &fds,
  901.     NULL, NULL, &waittime);
  902.   if (rc < 0 && errno != EINTR)
  903.     __glutFatalError("select error.");
  904. #else
  905. #if 0 /* XXX Nate, what is this junk? */
  906.   /* Set up a timer to fire in at least a millisecond, then wait for
  907.      the message.  This should act like a select. */
  908.   SetTimer(NULL, 2, waittime.tv_usec, NULL);
  909.   WaitMessage();
  910.   KillTimer(NULL, 2);
  911. #endif
  912.  
  913.   /* Actually, a sleep seems to do the trick -- do we even need this? */
  914.   Sleep(0);
  915. #endif
  916. #endif /* not vms6.2 or lower */
  917.   /* Without considering the cause of select unblocking, check
  918.      for pending X events and handle any timeouts (by calling
  919.      processEventsAndTimeouts).  We always look for X events
  920.      even if select returned with 0 (indicating a timeout);
  921.      otherwise we risk starving X event processing by continous
  922.      timeouts. */
  923.   if (XPending(__glutDisplay)) {
  924.   immediatelyHandleXinput:
  925.     processEventsAndTimeouts();
  926.   } else {
  927.     if (__glutTimerList)
  928.       handleTimeouts();
  929.   }
  930. }
  931.  
  932. static void
  933. idleWait(void)
  934. {
  935.   if (XPending(__glutDisplay)) {
  936.     processEventsAndTimeouts();
  937.   } else {
  938.     if (__glutTimerList) {
  939.       handleTimeouts();
  940.     }
  941.   }
  942.   /* Make sure idle func still exists! */
  943.   if (__glutIdleFunc) {
  944.     __glutIdleFunc();
  945.   }
  946. }
  947.  
  948. static GLUTwindow **beforeEnd;
  949.  
  950. static GLUTwindow *
  951. processWindowWorkList(GLUTwindow * window)
  952. {
  953.   int workMask;
  954.  
  955.   if (window->prevWorkWin) {
  956.     window->prevWorkWin = processWindowWorkList(window->prevWorkWin);
  957.   } else {
  958.     beforeEnd = &window->prevWorkWin;
  959.   }
  960.  
  961.   /* Capture work mask for work that needs to be done to this
  962.      window, then clear the window's work mask (excepting the
  963.      dummy work bit, see below).  Then, process the captured
  964.      work mask.  This allows callbacks in the processing the
  965.      captured work mask to set the window's work mask for
  966.      subsequent processing. */
  967.  
  968.   workMask = window->workMask;
  969.   assert((workMask & GLUT_DUMMY_WORK) == 0);
  970.  
  971.   /* Set the dummy work bit, clearing all other bits, to
  972.      indicate that the window is currently on the window work
  973.      list _and_ that the window's work mask is currently being
  974.      processed.  This convinces __glutPutOnWorkList that this
  975.      window is on the work list still. */
  976.   window->workMask = GLUT_DUMMY_WORK;
  977.  
  978.   /* Optimization: most of the time, the work to do is a
  979.      redisplay and not these other types of work.  Check for
  980.      the following cases as a group to before checking each one
  981.      individually one by one. This saves about 25 MIPS
  982.      instructions in the common redisplay only case. */
  983.   if (workMask & (GLUT_EVENT_MASK_WORK | GLUT_DEVICE_MASK_WORK |
  984.       GLUT_CONFIGURE_WORK | GLUT_COLORMAP_WORK | GLUT_MAP_WORK)) {
  985. #if !defined(_WIN32)
  986.     /* Be sure to set event mask BEFORE map window is done. */
  987.     if (workMask & GLUT_EVENT_MASK_WORK) {
  988.       long eventMask;
  989.  
  990.       /* Make sure children are not propogating events this
  991.          window is selecting for.  Be sure to do this before
  992.          enabling events on the children's parent. */
  993.       if (window->children) {
  994.         GLUTwindow *child = window->children;
  995.         unsigned long attribMask = CWDontPropagate;
  996.         XSetWindowAttributes wa;
  997.  
  998.         wa.do_not_propagate_mask = window->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
  999.         if (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK) {
  1000.           wa.event_mask = child->eventMask | (window->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
  1001.           attribMask |= CWEventMask;
  1002.         }
  1003.         do {
  1004.           XChangeWindowAttributes(__glutDisplay, child->win,
  1005.             attribMask, &wa);
  1006.           child = child->siblings;
  1007.         } while (child);
  1008.       }
  1009.       eventMask = window->eventMask;
  1010.       if (window->parent && window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
  1011.         eventMask |= (window->parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK);
  1012.       XSelectInput(__glutDisplay, window->win, eventMask);
  1013.       if (window->overlay)
  1014.         XSelectInput(__glutDisplay, window->overlay->win,
  1015.           window->eventMask & GLUT_OVERLAY_EVENT_FILTER_MASK);
  1016.     }
  1017. #endif /* !_WIN32 */
  1018.     /* Be sure to set device mask BEFORE map window is done. */
  1019.     if (workMask & GLUT_DEVICE_MASK_WORK) {
  1020.       __glutUpdateInputDeviceMaskFunc(window);
  1021.     }
  1022.     /* Be sure to configure window BEFORE map window is done. */
  1023.     if (workMask & GLUT_CONFIGURE_WORK) {
  1024. #if defined(_WIN32)
  1025.       RECT changes;
  1026.       POINT point;
  1027.       UINT flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER
  1028.     | SWP_NOSENDCHANGING | SWP_NOSIZE | SWP_NOZORDER;
  1029.  
  1030.       GetClientRect(window->win, &changes);
  1031.       
  1032.       /* If this window is a toplevel window, translate the 0,0 client
  1033.          coordinate into a screen coordinate for proper placement. */
  1034.       if (!window->parent) {
  1035.         point.x = 0;
  1036.         point.y = 0;
  1037.         ClientToScreen(window->win, &point);
  1038.         changes.left = point.x;
  1039.         changes.top = point.y;
  1040.       }
  1041.       if (window->desiredConfMask & (CWX | CWY)) {
  1042.         changes.left = window->desiredX;
  1043.         changes.top = window->desiredY;
  1044.     flags &= ~SWP_NOMOVE;
  1045.       }
  1046.       if (window->desiredConfMask & (CWWidth | CWHeight)) {
  1047.         changes.right = changes.left + window->desiredWidth;
  1048.         changes.bottom = changes.top + window->desiredHeight;
  1049.     flags &= ~SWP_NOSIZE;
  1050.     /* XXX If overlay exists, resize the overlay here, ie.
  1051.        if (window->overlay) ... */
  1052.       }
  1053.       if (window->desiredConfMask & CWStackMode) {
  1054.     flags &= ~SWP_NOZORDER;
  1055.     /* XXX Overlay support might require something special here. */
  1056.       }
  1057.  
  1058.       /* Adjust the window rectangle because Win32 thinks that the x, y,
  1059.          width & height are the WHOLE window (including decorations),
  1060.          whereas GLUT treats the x, y, width & height as only the CLIENT
  1061.          area of the window.  Only do this to top level windows
  1062.          that are not in game mode (since game mode windows do
  1063.          not have any decorations). */
  1064.       if (!window->parent && window != __glutGameModeWindow) {
  1065.         AdjustWindowRect(&changes,
  1066.           WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  1067.           FALSE);
  1068.       }
  1069.  
  1070.       /* Do the repositioning, moving, and push/pop. */
  1071.       SetWindowPos(window->win,
  1072.         window->desiredStack == Above ? HWND_TOP : HWND_NOTOPMOST,
  1073.         changes.left, changes.top,
  1074.         changes.right - changes.left, changes.bottom - changes.top,
  1075.         flags);
  1076.  
  1077.       /* Zero out the mask. */
  1078.       window->desiredConfMask = 0;
  1079.  
  1080.       /* This hack causes the window to go back to the right position
  1081.          when it is taken out of fullscreen mode. */
  1082.       if (workMask & GLUT_FULL_SCREEN_WORK) {
  1083.         window->desiredConfMask |= CWX | CWY;
  1084.         window->desiredX = point.x;
  1085.         window->desiredY = point.y;
  1086.       }
  1087. #else /* !_WIN32 */
  1088.       XWindowChanges changes;
  1089.  
  1090.       changes.x = window->desiredX;
  1091.       changes.y = window->desiredY;
  1092.       if (window->desiredConfMask & (CWWidth | CWHeight)) {
  1093.         changes.width = window->desiredWidth;
  1094.         changes.height = window->desiredHeight;
  1095.         if (window->overlay)
  1096.           XResizeWindow(__glutDisplay, window->overlay->win,
  1097.             window->desiredWidth, window->desiredHeight);
  1098.         if (__glutMotifHints != None) {
  1099.           if (workMask & GLUT_FULL_SCREEN_WORK) {
  1100.             MotifWmHints hints;
  1101.  
  1102.             hints.flags = MWM_HINTS_DECORATIONS;
  1103.             hints.decorations = 0;  /* Absolutely no
  1104.                                        decorations. */
  1105.             XChangeProperty(__glutDisplay, window->win,
  1106.               __glutMotifHints, __glutMotifHints, 32,
  1107.               PropModeReplace, (unsigned char *) &hints, 4);
  1108.             if (workMask & GLUT_MAP_WORK) {
  1109.               /* Handle case where glutFullScreen is called
  1110.                  before the first time that the window is
  1111.                  mapped. Some window managers will randomly or
  1112.                  interactively position the window the first
  1113.                  time it is mapped if the window's
  1114.                  WM_NORMAL_HINTS property does not request an
  1115.                  explicit position. We don't want any such
  1116.                  window manager interaction when going
  1117.                  fullscreen.  Overwrite the WM_NORMAL_HINTS
  1118.                  property installed by glutCreateWindow's
  1119.                  XSetWMProperties property with one explicitly
  1120.                  requesting a fullscreen window. */
  1121.               XSizeHints hints;
  1122.  
  1123.               hints.flags = USPosition | USSize;
  1124.               hints.x = 0;
  1125.               hints.y = 0;
  1126.               hints.width = window->desiredWidth;
  1127.               hints.height = window->desiredHeight;
  1128.               XSetWMNormalHints(__glutDisplay, window->win, &hints);
  1129.             }
  1130.           } else {
  1131.             XDeleteProperty(__glutDisplay, window->win, __glutMotifHints);
  1132.           }
  1133.         }
  1134.       }
  1135.       if (window->desiredConfMask & CWStackMode) {
  1136.         changes.stack_mode = window->desiredStack;
  1137.         /* Do not let glutPushWindow push window beneath the
  1138.            underlay. */
  1139.         if (window->parent && window->parent->overlay
  1140.           && window->desiredStack == Below) {
  1141.           changes.stack_mode = Above;
  1142.           changes.sibling = window->parent->overlay->win;
  1143.           window->desiredConfMask |= CWSibling;
  1144.         }
  1145.       }
  1146.       XConfigureWindow(__glutDisplay, window->win,
  1147.         window->desiredConfMask, &changes);
  1148.       window->desiredConfMask = 0;
  1149. #endif
  1150.     }
  1151. #if !defined(_WIN32)
  1152.     /* Be sure to establish the colormaps BEFORE map window is
  1153.        done. */
  1154.     if (workMask & GLUT_COLORMAP_WORK) {
  1155.       __glutEstablishColormapsProperty(window);
  1156.     }
  1157. #endif
  1158.     if (workMask & GLUT_MAP_WORK) {
  1159.       switch (window->desiredMapState) {
  1160.       case WithdrawnState:
  1161.         if (window->parent) {
  1162.           XUnmapWindow(__glutDisplay, window->win);
  1163.         } else {
  1164.           XWithdrawWindow(__glutDisplay, window->win,
  1165.             __glutScreen);
  1166.         }
  1167.         window->shownState = 0;
  1168.         break;
  1169.       case NormalState:
  1170.         XMapWindow(__glutDisplay, window->win);
  1171.         window->shownState = 1;
  1172.         break;
  1173. #ifdef _WIN32
  1174.       case GameModeState:  /* Not an Xlib value. */
  1175.         ShowWindow(window->win, SW_SHOW);
  1176.         window->shownState = 1;
  1177.         break;
  1178. #endif
  1179.       case IconicState:
  1180.         XIconifyWindow(__glutDisplay, window->win, __glutScreen);
  1181.         window->shownState = 0;
  1182.         break;
  1183.       }
  1184.     }
  1185.   }
  1186.   if (workMask & (GLUT_REDISPLAY_WORK | GLUT_OVERLAY_REDISPLAY_WORK | GLUT_REPAIR_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
  1187.     if (window->forceReshape) {
  1188.       /* Guarantee that before a display callback is generated
  1189.          for a window, a reshape callback must be generated. */
  1190.       __glutSetWindow(window);
  1191.       window->reshape(window->width, window->height);
  1192.       window->forceReshape = False;
  1193.  
  1194.       /* Setting the redisplay bit on the first reshape is
  1195.          necessary to make the "Mesa glXSwapBuffers to repair
  1196.          damage" hack operate correctly.  Without indicating a
  1197.          redisplay is necessary, there's not an initial back
  1198.          buffer render from which to blit from when damage
  1199.          happens to the window. */
  1200.       workMask |= GLUT_REDISPLAY_WORK;
  1201.     }
  1202.     /* The code below is more involved than otherwise necessary
  1203.        because it is paranoid about the overlay or entire window
  1204.        being removed or destroyed in the course of the callbacks.
  1205.        Notice how the global __glutWindowDamaged is used to record
  1206.        the layers' damage status.  See the code in glutLayerGet for
  1207.        how __glutWindowDamaged is used. The  point is to not have to
  1208.        update the "damaged" field after  the callback since the
  1209.        window (or overlay) may be destroyed (or removed) when the
  1210.        callback returns. */
  1211.  
  1212.     if (window->overlay && window->overlay->display) {
  1213.       int num = window->num;
  1214.       Window xid = window->overlay ? window->overlay->win : None;
  1215.  
  1216.       /* If an overlay display callback is registered, we
  1217.          differentiate between a redisplay needed for the
  1218.          overlay and/or normal plane.  If there is no overlay
  1219.          display callback registered, we simply use the
  1220.          standard display callback. */
  1221.  
  1222.       if (workMask & (GLUT_REDISPLAY_WORK | GLUT_REPAIR_WORK)) {
  1223.         if (__glutMesaSwapHackSupport) {
  1224.           if (window->usedSwapBuffers) {
  1225.             if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
  1226.               glXSwapBuffers(__glutDisplay, window->win);
  1227.               goto skippedDisplayCallback1;
  1228.             }
  1229.           }
  1230.         }
  1231.         /* Render to normal plane. */
  1232.         window->renderWin = window->win;
  1233.         window->renderCtx = window->ctx;
  1234.         __glutWindowDamaged = (workMask & GLUT_REPAIR_WORK);
  1235.         __glutSetWindow(window);
  1236.         window->usedSwapBuffers = 0;
  1237.         window->display();
  1238.         __glutWindowDamaged = 0;
  1239.  
  1240.       skippedDisplayCallback1:;
  1241.       }
  1242.       if (workMask & (GLUT_OVERLAY_REDISPLAY_WORK | GLUT_OVERLAY_REPAIR_WORK)) {
  1243.         window = __glutWindowList[num];
  1244.         if (window && window->overlay &&
  1245.           window->overlay->win == xid && window->overlay->display) {
  1246.  
  1247.           /* Render to overlay. */
  1248.           window->renderWin = window->overlay->win;
  1249.           window->renderCtx = window->overlay->ctx;
  1250.           __glutWindowDamaged = (workMask & GLUT_OVERLAY_REPAIR_WORK);
  1251.           __glutSetWindow(window);
  1252.           window->overlay->display();
  1253.           __glutWindowDamaged = 0;
  1254.         } else {
  1255.           /* Overlay may have since been destroyed or the
  1256.              overlay callback may have been disabled during
  1257.              normal display callback. */
  1258.         }
  1259.       }
  1260.     } else {
  1261.       if (__glutMesaSwapHackSupport) {
  1262.         if (!window->overlay && window->usedSwapBuffers) {
  1263.           if ((workMask & (GLUT_REPAIR_WORK | GLUT_REDISPLAY_WORK)) == GLUT_REPAIR_WORK) {
  1264.             glXSwapBuffers(__glutDisplay, window->win);
  1265.             goto skippedDisplayCallback2;
  1266.           }
  1267.         }
  1268.       }
  1269.       /* Render to normal plane (and possibly overlay). */
  1270.       __glutWindowDamaged = (workMask & (GLUT_OVERLAY_REPAIR_WORK | GLUT_REPAIR_WORK));
  1271.       __glutSetWindow(window);
  1272.       window->usedSwapBuffers = 0;
  1273.       window->display();
  1274.       __glutWindowDamaged = 0;
  1275.  
  1276.     skippedDisplayCallback2:;
  1277.     }
  1278.   }
  1279.   /* Combine workMask with window->workMask to determine what
  1280.      finish and debug work there is. */
  1281.   workMask |= window->workMask;
  1282.  
  1283.   if (workMask & GLUT_FINISH_WORK) {
  1284.     /* Finish work makes sure a glFinish gets done to indirect
  1285.        rendering contexts.  Indirect contexts tend to have much 
  1286.        longer latency because lots of OpenGL extension requests 
  1287.        can queue up in the X protocol stream. __glutSetWindow
  1288.        is where the finish works gets queued for indirect
  1289.        contexts. */
  1290.     __glutSetWindow(window);
  1291.     glFinish();
  1292.   }
  1293.   if (workMask & GLUT_DEBUG_WORK) {
  1294.     __glutSetWindow(window);
  1295.     glutReportErrors();
  1296.   }
  1297.   /* Strip out dummy, finish, and debug work bits. */
  1298.   window->workMask &= ~(GLUT_DUMMY_WORK | GLUT_FINISH_WORK | GLUT_DEBUG_WORK);
  1299.   if (window->workMask) {
  1300.     /* Leave on work list. */
  1301.     return window;
  1302.   } else {
  1303.     /* Remove current window from work list. */
  1304.     return window->prevWorkWin;
  1305.   }
  1306. }
  1307.  
  1308. /* CENTRY */
  1309. void APIENTRY
  1310. glutMainLoop(void)
  1311. {
  1312. #if !defined(_WIN32)
  1313.   if (!__glutDisplay)
  1314.     __glutFatalUsage("main loop entered with out proper initialization.");
  1315. #endif
  1316.   if (!__glutWindowListSize)
  1317.     __glutFatalUsage(
  1318.       "main loop entered with no windows created.");
  1319.   for (;;) {
  1320.     if (__glutWindowWorkList) {
  1321.       GLUTwindow *remainder, *work;
  1322.  
  1323.       work = __glutWindowWorkList;
  1324.       __glutWindowWorkList = NULL;
  1325.       if (work) {
  1326.         remainder = processWindowWorkList(work);
  1327.         if (remainder) {
  1328.           *beforeEnd = __glutWindowWorkList;
  1329.           __glutWindowWorkList = remainder;
  1330.         }
  1331.       }
  1332.     }
  1333.     if (__glutIdleFunc || __glutWindowWorkList) {
  1334.       idleWait();
  1335.     } else {
  1336.       if (__glutTimerList) {
  1337.         waitForSomething();
  1338.       } else {
  1339.         processEventsAndTimeouts();
  1340.       }
  1341.     }
  1342.   }
  1343. }
  1344. /* ENDCENTRY */
  1345.